package com.waimai1.waimai.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.waimai1.waimai.common.AesUtil;
import com.waimai1.waimai.common.BaseContext;
import com.waimai1.waimai.common.Utils;
import com.waimai1.waimai.config.PartnerPayConfig;
import com.waimai1.waimai.config.PayConfig;
import com.waimai1.waimai.entity.*;
import com.waimai1.waimai.exception.EnumException;
import com.waimai1.waimai.exception.NotErrorException;
import com.waimai1.waimai.service.*;
import com.wechat.pay.java.core.notification.Notification;
import com.wechat.pay.java.core.notification.Resource;

import com.wechat.pay.java.service.partnerpayments.jsapi.JsapiService;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.*;
import com.wechat.pay.java.service.profitsharing.ProfitsharingService;
import com.wechat.pay.java.service.profitsharing.model.*;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.management.relation.RelationType;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class LocalWepayServiceImpl implements LocalWepayService {

//    @Value("${wxPay.appid}")
//    private String appid;
    @Value("${wxPay.partnerMchid}")
    private String mchid;
    @Value("${partnerWePayNotifyUrl}")
    private String notify;
    @Value("${wePayRefundNotify}")
    private String RefundNotify;
    @Value("${wxPay.partnerApiV3key}")
    private String apiV3key;
    @Autowired
    private AcidService acidService;
    @Autowired
    private WepayOrderService wepayOrderService;
    @Autowired
    private HwOrderService hwOrderService;
    @Autowired
    private MyOrderService orderService;
    @Autowired
    private LocalShopService localShopService;
    @Autowired
    private CommissionService commissionService;
    public static RefundService refundService;
    public static ProfitsharingService service;

    @Override
    public PrepayResponse localPrepay(int totalFee, String openid, String tradeNo,Integer shopId,boolean fenzhang) {
        JsapiService service = new JsapiService.Builder().config(PartnerPayConfig.partnerConfig).build();
        LocalShop localShop=localShopService.getById(shopId);
        PrepayRequest request = new PrepayRequest();
        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
        Acid resAcid=acidService.getById(BaseContext.getAcid());
        request.setSpAppid(resAcid.getAppid());
        request.setSpMchid(mchid);
        request.setSubMchid(localShop.getSubMchid());
        request.setDescription("蓝臣科技本地商户-付款");
        request.setOutTradeNo(tradeNo);
        request.setNotifyUrl(notify);
        Amount amount = new Amount();
        amount.setTotal(totalFee);
        amount.setCurrency("CNY");
        request.setAmount(amount);
        Payer payer = new Payer();
        payer.setSpOpenid(openid);
        request.setPayer(payer);
//        需要分账的情况
        if(fenzhang){
            SettleInfo settleInfo=new SettleInfo();
            settleInfo.setProfitSharing(true);
            request.setSettleInfo(settleInfo);
        }
        // 调用接口

        return service.prepay(request);
    }
    /**
     * 微信支付回调
     *
     * @param request 请求
     * @return 结果
     */
    @Override
    public JSONObject getResource(HttpServletRequest request) throws IOException, GeneralSecurityException {
        // TODO 必须使用request获取body（readLine读取），微信推送的消息使用@RequestBody可能一次性无法读完，造成解密失败
        String streamReadString = getRequestBody(request);
        Notification notification = JSONObject.parseObject(streamReadString, Notification.class);
        log.info("pay callback: request read={}", streamReadString);
        log.info("pay callback: request read={}", notification.toString());
        if (("支付成功").equals(notification.getSummary())) {
            Resource resource = notification.getResource();
            String associatedData = resource.getAssociatedData();
            String nonce = resource.getNonce();
            String ciphertext = resource.getCiphertext();
            byte[] associatedDataBytes = associatedData.getBytes("UTF-8");
            byte[] nonceBytes = nonce.getBytes("UTF-8");
            AesUtil aesUtil = new AesUtil(apiV3key.getBytes("utf-8"));
            String resourcedData = aesUtil.decryptToString(associatedDataBytes, nonceBytes, ciphertext);
            log.info("resourceData:" + resourcedData);
            // 解密得到的json结果
            JSONObject decryptedJsonObj = JSONObject.parseObject(resourcedData);
            return decryptedJsonObj;
        }
        return null;
    }

    /**
     * 获取请求体
     *
     * @param request 请求
     */
    private String getRequestBody(HttpServletRequest request) {
        ServletInputStream stream = null;
        BufferedReader reader = null;
        StringBuilder sb = new StringBuilder();
        try {
            stream = request.getInputStream();
            // 获取响应
            reader = new BufferedReader(new InputStreamReader(stream));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            assert stream != null;
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            assert reader != null;
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return sb.toString();
    }

    /**
     * 退款申请
     */
    //全额退
    public void allRefund(MyOrder order){
        LambdaQueryWrapper<WepayOrder> wepayOrderServiceLambdaQueryWrapper=new LambdaQueryWrapper<>();
        wepayOrderServiceLambdaQueryWrapper.eq(WepayOrder::getOutTradeNo,order.getOutTradeNo());
        WepayOrder wepayOrder=wepayOrderService.getOne(wepayOrderServiceLambdaQueryWrapper);
        if(null==wepayOrder){
            throw new NotErrorException(EnumException.NO_WEPAY_ORDER);
        }
        Refund res=refund(order.getOutTradeNo(),(long)wepayOrder.getTotal(),(long)wepayOrder.getTotal());
        if(!("SUCCESS".equals(res.getStatus().name()))){
            throw new NotErrorException(1006,"退款失败"+res.getStatus());
        }
        order.setOutRefundNo(res.getOutRefundNo());
        order.setStatus(Utils.STATUS_REFUNDED);
        if(orderService.updateById(order)){
            throw new NotErrorException(1007,"退款异常"+res.getStatus());
        };
    }
    //全额退
    public void partRefund(MyOrder order){
        LambdaQueryWrapper<WepayOrder> wepayOrderServiceLambdaQueryWrapper=new LambdaQueryWrapper<>();
        wepayOrderServiceLambdaQueryWrapper.eq(WepayOrder::getOutTradeNo,order.getOutTradeNo());
        WepayOrder wepayOrder=wepayOrderService.getOne(wepayOrderServiceLambdaQueryWrapper);
        if(null==wepayOrder){
            throw new NotErrorException(EnumException.NO_WEPAY_ORDER);
        }
        LambdaQueryWrapper<HwOrder> hwOrderLambdaQueryWrapper=new LambdaQueryWrapper<>();
        hwOrderLambdaQueryWrapper.eq(HwOrder::getTradeNo,order.getOutTradeNo());
        HwOrder hwOrder=hwOrderService.getOne(hwOrderLambdaQueryWrapper);
        if(null==hwOrder){
            throw new NotErrorException(EnumException.NO_HW_ORDER);
        }
        //计算退款金额，为hw退款加上抽成，可能有略高得情况
        List<Commission> commissions=commissionService.list();
        Long partialRefundPrice=Long.parseLong(hwOrder.getPartialRefundPrice());
        for(Commission item : commissions){
            //单位为分
            if(order.getMovieName().equals(item.getBrandName())){
                if(item.getStatus()==1){
                    if(item.getPercent().equals("百分比")){
                        partialRefundPrice= Math.round(partialRefundPrice*item.getCount()+partialRefundPrice);
                    }else if(item.getPercent().equals("金额")){
                        partialRefundPrice= (long)(partialRefundPrice+item.getCount())*100;
                    }
                }else{
                    partialRefundPrice=partialRefundPrice*100;
                }
                break;
            }
        }
        Refund res=refund(order.getOutTradeNo(),partialRefundPrice,(long)wepayOrder.getTotal());
        if(!("SUCCESS".equals(res.getStatus().name()))){
            throw new NotErrorException(1006,"退款失败"+res.getStatus());
        }
        order.setOutRefundNo(res.getOutRefundNo());
        order.setStatus(Utils.STATUS_REFUNDED);
        if(orderService.updateById(order)){
            throw new NotErrorException(1007,"退款异常"+res.getStatus());
        };
    }
    public Refund refund(String out_trade_no, Long refundAmount,Long totalAmount) {
        refundService = new RefundService.Builder().config(PayConfig.config).build();
        // ... 调用接口
        CreateRequest request = new CreateRequest();
        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
        request.setOutTradeNo(out_trade_no);
        request.setOutRefundNo("TK" + out_trade_no);
        request.setNotifyUrl(RefundNotify);
        AmountReq amountReq = new AmountReq();
        amountReq.setRefund(refundAmount);
        amountReq.setTotal(totalAmount);
        amountReq.setCurrency("CNY");
        request.setAmount(amountReq);
        // 调用接口
        return refundService.create(request);
    }

    /** 添加分账接收方API */
    @Override
    public AddReceiverResponse addReceiver(String subMchid, ReceiverType type, String account, ReceiverRelationType relationType) {
        service = new ProfitsharingService.Builder().config(PartnerPayConfig.partnerConfig).build();
        AddReceiverRequest request = new AddReceiverRequest();
        Acid resAcid=acidService.getById(BaseContext.getAcid());

        request.setAppid(resAcid.getAppid());
        request.setSubMchid(subMchid);
        request.setType(type);
        request.setAccount(account);
        request.setRelationType(relationType);
        return service.addReceiver(request);
    }

    /** 请求分账API */
    @Override
    public OrdersEntity createFenzhang(String subMchid,String transaction_id,String out_order_no,ArrayList<CreateOrderReceiver> receivers) {
        service = new ProfitsharingService.Builder().config(PartnerPayConfig.partnerConfig).build();
        CreateOrderRequest request = new CreateOrderRequest();
        Acid resAcid=acidService.getById(BaseContext.getAcid());
        request.setAppid(resAcid.getAppid());
        request.setSubMchid(subMchid);
        request.setTransactionId(transaction_id);
        request.setOutOrderNo(out_order_no);
        request.setReceivers(receivers);
        request.setUnfreezeUnsplit(true);
        return service.createOrder(request);
    }
}
